Skip to content

Potential fix for code scanning alert no. 23: Clear text storage of sensitive information#71

Merged
DarkModder33 merged 1 commit intomainfrom
alert-autofix-23
Feb 17, 2026
Merged

Potential fix for code scanning alert no. 23: Clear text storage of sensitive information#71
DarkModder33 merged 1 commit intomainfrom
alert-autofix-23

Conversation

@DarkModder33
Copy link
Copy Markdown
Owner

@DarkModder33 DarkModder33 commented Feb 17, 2026

Potential fix for https://github.com/DarkModder33/main/security/code-scanning/23

In general, the safest approach is to avoid persisting sensitive identifiers in clear text at all. Here, localStorage is used purely as a caching/fallback layer for leaderboard data; there is no strict need to cache oauthProvider or oauthUserId locally. Instead, we can strip these properties (and any other sensitive identity fields we want to treat cautiously) before writing the data to localStorage, while still keeping them in memory and in server submissions.

Concretely, in app/game/GamePageClient.tsx we will:

  1. Leave the submission and entry objects unchanged at creation time; they still include oauthProvider, oauthUserId, and walletAddress so game logic and server API calls remain intact.
  2. Before persisting leaderboard entries into localStorage (both in persistLocal and in the response.ok branch of submit), map the entries to a “public” shape that omits oauthProvider and oauthUserId (and any additional sensitive fields we decide to exclude). For example, create publicEntries = merged.map(stripSensitiveLeaderboardFields) and store that instead.
  3. Implement a small helper function stripSensitiveLeaderboardFields inside this component file that takes a LeaderboardEntry and returns a copy with sensitive fields dropped. This function will be used only right before localStorage writes.
  4. Keep setLeaderboardEntries working with full entries as before, using the original arrays (top or payload.entries) so that in‑memory behavior is unchanged. Only the data written to localStorage is sanitized.

No additional external dependencies are required. The only code additions are the helper function and minor changes in the persistLocal and submit logic where localStorage.setItem is called.

Suggested fixes powered by Copilot Autofix. Review carefully before merging.

Summary by Sourcery

Sanitize leaderboard data before caching it locally to avoid storing sensitive OAuth identifiers in clear text.

Bug Fixes:

  • Prevent clear-text storage of sensitive OAuth identifiers in leaderboard data persisted to localStorage.

Enhancements:

  • Introduce a helper to strip sensitive identity fields from leaderboard entries just before they are written to localStorage, while keeping in-memory data unchanged.

…ensitive information

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Feb 17, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
main Error Error Feb 17, 2026 4:43am
tradeai Error Error Feb 17, 2026 4:43am

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Feb 17, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Sanitizes leaderboard data before writing it to localStorage by introducing a helper that strips sensitive OAuth identifiers, and updates the leaderboard persistence logic to use this sanitized representation while keeping full entries in memory and for server interactions.

Sequence diagram for submitting leaderboard entry with sanitized localStorage caching

sequenceDiagram
  actor Player
  participant GamePage
  participant ServerAPI
  participant LocalStorage

  Player->>GamePage: submitScore(entry)
  GamePage->>ServerAPI: POST /leaderboard with full entry
  ServerAPI-->>GamePage: payload.entries (full LeaderboardEntry[])
  GamePage->>GamePage: setLeaderboardEntries(payload.entries)
  GamePage->>GamePage: topEntries = payload.entries.slice(0, 50)
  GamePage->>GamePage: publicTopEntries = topEntries.map(stripSensitiveLeaderboardFields)
  GamePage->>LocalStorage: setItem(LEADERBOARD_STORAGE_KEY, JSON.stringify(publicTopEntries))
  Player-->>Player: Full entries kept in memory only
Loading

Class diagram for sanitized leaderboard persistence

classDiagram
  class LeaderboardEntry {
    +string id
    +string name
    +number score
    +string oauthProvider
    +string oauthUserId
    +string walletAddress
  }

  class GamePage {
    +persistLocal(entry LeaderboardEntry) void
    +submit(entry LeaderboardEntry) Promise~void~
    +setLeaderboardEntries(entries LeaderboardEntry[]) void
  }

  class stripSensitiveLeaderboardFields {
    +stripSensitiveLeaderboardFields(entry LeaderboardEntry) LeaderboardEntry
  }

  GamePage --> LeaderboardEntry : uses
  GamePage ..> stripSensitiveLeaderboardFields : calls

  %% Implementation detail of stripSensitiveLeaderboardFields
  class stripSensitiveLeaderboardFieldsImpl {
    +oauthProvider undefined
    +oauthUserId undefined
  }
  stripSensitiveLeaderboardFields --> LeaderboardEntry : returns sanitized copy
  stripSensitiveLeaderboardFieldsImpl --|> LeaderboardEntry
Loading

File-Level Changes

Change Details Files
Introduce a helper to strip sensitive identity fields from leaderboard entries before caching them locally.
  • Add stripSensitiveLeaderboardFields function that omits oauthProvider and oauthUserId from a leaderboard entry and sets them to undefined in the returned object.
  • Ensure the helper is typed to return LeaderboardEntry so it can be mapped over existing arrays without broader type changes.
app/game/GamePageClient.tsx
Sanitize leaderboard entries before persisting them to localStorage while retaining full data in memory and API flows.
  • In persistLocal, map the sorted top leaderboard entries through stripSensitiveLeaderboardFields before JSON.stringify and localStorage.setItem, while still calling setLeaderboardEntries with the full top entries.
  • In submit success handling, slice payload.entries to the top 50, map them through stripSensitiveLeaderboardFields for localStorage storage, but keep setLeaderboardEntries using the full payload.entries array.
app/game/GamePageClient.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@DarkModder33 DarkModder33 marked this pull request as ready for review February 17, 2026 04:42
@DarkModder33 DarkModder33 merged commit 937d090 into main Feb 17, 2026
11 of 19 checks passed
@DarkModder33 DarkModder33 deleted the alert-autofix-23 branch February 17, 2026 04:42
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • The stripSensitiveLeaderboardFields helper currently asserts the result as LeaderboardEntry while setting oauthProvider/oauthUserId to undefined; consider introducing a PublicLeaderboardEntry = Omit<LeaderboardEntry, 'oauthProvider' | 'oauthUserId'> type and using that for localStorage to avoid misleading types and required fields being undefined.
  • If there are or will be other persistence paths for leaderboard data, it may be safer to centralize this sanitization in a shared utility (e.g., a sanitizeLeaderboardForStorage helper) so that any new storage usage automatically omits sensitive fields.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The `stripSensitiveLeaderboardFields` helper currently asserts the result as `LeaderboardEntry` while setting `oauthProvider`/`oauthUserId` to `undefined`; consider introducing a `PublicLeaderboardEntry = Omit<LeaderboardEntry, 'oauthProvider' | 'oauthUserId'>` type and using that for localStorage to avoid misleading types and required fields being `undefined`.
- If there are or will be other persistence paths for leaderboard data, it may be safer to centralize this sanitization in a shared utility (e.g., a `sanitizeLeaderboardForStorage` helper) so that any new storage usage automatically omits sensitive fields.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant